package org.jeecg.modules.wms.outorder.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.wms.config.WarehouseDictEnum;
import org.jeecg.modules.wms.inventory.entity.WmsInventory;
import org.jeecg.modules.wms.inventory.service.IWmsInventoryService;
//import org.jeecg.modules.wms.inventory.service.impl.WmsInventoryTransByAllocation;
import org.jeecg.modules.wms.inventory.service.impl.WmsInventoryTransByAllocation;
import org.jeecg.modules.wms.inventory.vo.WmsInventoryTransParam;
import org.jeecg.modules.wms.outorder.entity.WmsOutOrders;
import org.jeecg.modules.wms.outorder.entity.WmsOutOrdersAllocation;
import org.jeecg.modules.wms.outorder.entity.WmsOutOrdersItems;
import org.jeecg.modules.wms.outorder.mapper.WmsOutOrdersItemsMapper;
import org.jeecg.modules.wms.outorder.mapper.WmsOutOrdersMapper;
import org.jeecg.modules.wms.outorder.service.IWmsOutOrdersAllocationService;
import org.jeecg.modules.wms.outorder.service.IWmsOutOrdersItemsService;
import org.jeecg.modules.wms.outorder.service.IWmsOutOrdersService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 出库单
 * @Author: jeecg-boot
 * @Date:   2025-05-19
 * @Version: V1.0
 */
@Service
public class WmsOutOrdersServiceImpl extends ServiceImpl<WmsOutOrdersMapper, WmsOutOrders> implements IWmsOutOrdersService {

	@Autowired
	private WmsOutOrdersMapper wmsOutOrdersMapper;
	@Autowired
	private WmsOutOrdersItemsMapper wmsOutOrdersItemsMapper;
	@Autowired
	private IWmsOutOrdersItemsService wmsOutOrdersItemsService;
	//注入库存service
	@Autowired
	private IWmsInventoryService wmsInventoryService;

	@Autowired
	private WmsInventoryTransByAllocation wmsInventoryTransByAllocation;

	//注入自己
	@Autowired
	private IWmsOutOrdersService owner;

	//注入wmsOutOrdersAllocationService
	@Autowired
	private IWmsOutOrdersAllocationService outOrdersAllocationService;

	@Autowired
	private RedisUtil redisUtil;

	@Override
	public IPage<WmsOutOrders> queryList(WmsOutOrders wmsOutOrders, Integer pageNo, Integer pageSize) {
		Page<WmsOutOrders> page = PageHelper.startPage(pageNo, pageSize);
		List<WmsOutOrders> list = wmsOutOrdersMapper.queryList(wmsOutOrders);
		PageDTO<WmsOutOrders> wmsOutOrdersPageDTO = new PageDTO<>();
		wmsOutOrdersPageDTO.setRecords(list);
		wmsOutOrdersPageDTO.setTotal(page.getTotal());
		wmsOutOrdersPageDTO.setSize(page.getPageSize());
		wmsOutOrdersPageDTO.setCurrent(page.getPageNum());
		wmsOutOrdersPageDTO.setPages(page.getPages());
		return wmsOutOrdersPageDTO;
	}
	/**
	 * 新增出库单
	 */
	public void add(WmsOutOrders wmsOutOrders){
		//生成出库单号
		String orderNumber = generateOrderNumber();
		wmsOutOrders.setOrderNo(orderNumber);
		//状态默认为创建状态 "CREATED"
		wmsOutOrders.setStatus(WarehouseDictEnum.OUTBOUND_CREATED.getCode());
		wmsOutOrdersMapper.insert(wmsOutOrders);
	}
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveMain(WmsOutOrders wmsOutOrders, List<WmsOutOrdersItems> wmsOutOrdersItemsList) {
		//生成出库单号
		String orderNumber = generateOrderNumber();
		wmsOutOrders.setOrderNo(orderNumber);
		//状态默认为创建状态 "CREATED"
		wmsOutOrders.setStatus(WarehouseDictEnum.OUTBOUND_CREATED.getCode());
		wmsOutOrdersMapper.insert(wmsOutOrders);
		//总商品数量
		int totalQuantity = 0;
		if(wmsOutOrdersItemsList!=null && wmsOutOrdersItemsList.size()>0) {
			for(WmsOutOrdersItems entity:wmsOutOrdersItemsList) {
				//商品数量
				totalQuantity += entity.getExpectedQuantity();
				//外键设置
				entity.setOrderId(wmsOutOrders.getId());
				//状态默认为创建状态 "CREATED"
				entity.setStatus(WarehouseDictEnum.OUTBOUND_DETAIL_CREATED.getCode());
				wmsOutOrdersItemsMapper.insert(entity);
			}
		}
		//更新商品数量
		wmsOutOrders.setTotalQuantity(totalQuantity);
		//商品sku种类数
		wmsOutOrders.setTotalSku(wmsOutOrdersItemsList.size());
		wmsOutOrdersMapper.updateById(wmsOutOrders);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateMain(WmsOutOrders wmsOutOrders,List<WmsOutOrdersItems> wmsOutOrdersItemsList) {
		wmsOutOrdersMapper.updateById(wmsOutOrders);

		//1.先删除子表数据
		wmsOutOrdersItemsMapper.deleteByMainId(wmsOutOrders.getId());

		//总商品数量
		int totalQuantity = 0;
		if(wmsOutOrdersItemsList!=null && wmsOutOrdersItemsList.size()>0) {
			for(WmsOutOrdersItems entity:wmsOutOrdersItemsList) {
				//商品数量
				totalQuantity += entity.getExpectedQuantity();
				//外键设置
				entity.setOrderId(wmsOutOrders.getId());
				//状态默认为创建状态 "CREATED"
				entity.setStatus(WarehouseDictEnum.OUTBOUND_DETAIL_CREATED.getCode());
				wmsOutOrdersItemsMapper.insert(entity);
			}
		}
		//更新商品数量
		wmsOutOrders.setTotalQuantity(totalQuantity);
		//商品sku种类数
		wmsOutOrders.setTotalSku(wmsOutOrdersItemsList.size());
		wmsOutOrdersMapper.updateById(wmsOutOrders);

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delMain(String id) {
		//出库单状态为创建状态或审核失败状态可以删除
		WmsOutOrders wmsOutOrders = wmsOutOrdersMapper.selectById(id);
		if(!(WarehouseDictEnum.OUTBOUND_CREATED.getCode().equals(wmsOutOrders.getStatus())
				|| WarehouseDictEnum.OUTBOUND_REJECTED.getCode().equals(wmsOutOrders.getStatus()))){
			throw new JeecgBootException("非创建状态、审核失败状态出库单不允许删除");
		}
		wmsOutOrdersItemsMapper.deleteByMainId(id);
		wmsOutOrdersMapper.deleteById(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delBatchMain(Collection<? extends Serializable> idList) {
		for(Serializable id:idList) {
			//出库单状态为创建状态或审核失败状态可以删除
			WmsOutOrders wmsOutOrders = wmsOutOrdersMapper.selectById(id);
			if(!(WarehouseDictEnum.OUTBOUND_CREATED.getCode().equals(wmsOutOrders.getStatus())
					|| WarehouseDictEnum.OUTBOUND_REJECTED.getCode().equals(wmsOutOrders.getStatus()))){
				throw new JeecgBootException("非创建状态、审核失败状态出库单不允许删除");
			}
			wmsOutOrdersItemsMapper.deleteByMainId(id.toString());
			wmsOutOrdersMapper.deleteById(id);
		}
	}

	public String generateOrderNumber() {
		//当前8位时间戳(年月日)"-"
		String time = DateUtils.now().substring(0, 10).replace("-", "");
		//key
		String key = "asn_number"+time;
		long incr = redisUtil.incr(key, 1);
		if(incr == 1){
			//设置过期时间，设置24小时+10秒的目的是避免并发产生订单号重复
			redisUtil.expire(key, 24*60*60+10);
		}
		//将incr组成4位字符串
		String incrStr = String.format("%04d", incr);
		String orderNumber = "OBD"+time+incrStr;

		return orderNumber;
	}

	/**
	 * 分配库存
	 * @param ids 出库单ID集合
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public int allocateStock(List<String> ids) {
		//分配成功数量
		int allocatedCount=0;

		//遍历出库单
		for(String orderId:ids) {
			//查询出库单
			WmsOutOrders wmsOutOrders = wmsOutOrdersMapper.selectById(orderId);
			//仓库id
			String warehouseId = wmsOutOrders.getWarehouseId();
			//出库单状态
			String status = wmsOutOrders.getStatus();
			//状态为审核通过状态或分配失败时才能继续
			if(!(WarehouseDictEnum.OUTBOUND_APPROVED.getCode().equals(status))
					&&!(WarehouseDictEnum.OUTBOUND_FAILED.getCode().equals(status))){
				continue;
			}
			//查询出库单明细
			List<WmsOutOrdersItems> skuItems = wmsOutOrdersItemsService.selectByMainId(orderId);
			//找到未分配的出库单明细(状态为创建或状态为分配失败)
			List<WmsOutOrdersItems> unAllocatedItems = skuItems.stream()
					.filter(item -> WarehouseDictEnum.OUTBOUND_DETAIL_CREATED.getCode().equals(item.getStatus()) || WarehouseDictEnum.OUTBOUND_DETAIL_FAILED.getCode().equals(item.getStatus()))
					.collect(Collectors.toList());
			if(CollectionUtils.isEmpty(unAllocatedItems)){
				continue;
			}
			//遍历未分配的出库单明细
			 for(WmsOutOrdersItems skuItem:unAllocatedItems) {
				 //查询可用库存列表
				 List<WmsInventory> wmsInventories = wmsInventoryService.selectAvailableBySku(warehouseId, skuItem);

				 //进行库存分配
				 String s = allocateStockToItems(skuItem, wmsInventories);

			 }

			 //更新出库单分配状态
			String allocateStatus = updateAllocateStatus(orderId);

			//计算分配成功的数量
			if(allocateStatus.equals(WarehouseDictEnum.OUTBOUND_ALLOCATED.getCode())){
				allocatedCount ++;
			}

		}



		return allocatedCount;
	}


	/**
	 * 更新出库单分配状态
	 */
	@Override
	public String updateAllocateStatus(String orderId) {
		//查询出库单明细
		List<WmsOutOrdersItems> skuItems = wmsOutOrdersItemsService.selectByMainId(orderId);
		//skuItem中的状态有一个是分配失败则出库单的状态为分配失败，否则分配成功，用stream流实现
		WarehouseDictEnum allocateStatus = skuItems.stream()
				.filter(item -> WarehouseDictEnum.OUTBOUND_DETAIL_FAILED.getCode().equals(item.getStatus()))
				.findAny()
				.map(item -> WarehouseDictEnum.OUTBOUND_FAILED)
				.orElse(WarehouseDictEnum.OUTBOUND_ALLOCATED);

		wmsOutOrdersMapper.update(null,
				new LambdaUpdateWrapper<WmsOutOrders>().eq(WmsOutOrders::getId,orderId)
						.and(wq->wq.eq(WmsOutOrders::getStatus, WarehouseDictEnum.OUTBOUND_APPROVED.getCode())
								.or()
								.eq(WmsOutOrders::getStatus, WarehouseDictEnum.OUTBOUND_FAILED.getCode()))
						.set(WmsOutOrders::getStatus,allocateStatus.getCode()));
		//返回分配状态
		return allocateStatus.getCode();
	}

	/**
	 * 更新出库单的拣货状态
	 */
	public void updatePickStatus(List<String> orderIds){
		//根据出库单id查询状态非拣货完成的记录
		List<WmsOutOrdersItems> wmsOutOrdersItemsNotPicked = wmsOutOrdersItemsService.selectNotPickedOrderItemsByOrderId(orderIds);
		//提取出出库单ID
		List<String> orderIdsNotPicked = wmsOutOrdersItemsNotPicked.stream().map(item -> item.getOrderId()).distinct().collect(Collectors.toList());
		//取出orderIds中不存在orderIdsNotPicked的记录
		List<String> orderIdsPicked = orderIds.stream()
				.filter(orderId -> !orderIdsNotPicked.contains(orderId))
				.collect(Collectors.toList());
		//更新 出库单 的拣货状态为拣货完成
		LambdaUpdateWrapper<WmsOutOrders> set = new LambdaUpdateWrapper<WmsOutOrders>()
				.in(WmsOutOrders::getId, orderIdsPicked)
				.eq(WmsOutOrders::getStatus, WarehouseDictEnum.OUTBOUND_PICKING.getCode())
				.set(WmsOutOrders::getStatus, WarehouseDictEnum.OUTBOUND_PICKED.getCode());
		int update = wmsOutOrdersMapper.update(null, set);
		if(update<=0){
			throw new JeecgBootException("为出库单拣货数量及状态失败!");
		}
	}

	/**
	 * 提交审核
	 * @param id
	 */
	public void submitAudit(String id){
		//如果没有选择出库单则返回错误
		if( oConvertUtils.isEmpty(id)){
			//抛出异常
			throw new JeecgBootException("请选择要审核的出库单");
		}
		WmsOutOrders wmsOutOrdersEntity = getById(id);
		if(wmsOutOrdersEntity==null) {
			//异常
			throw new JeecgBootException("出库单不存在");
		}
		//当前状态只能是创建状态、审核失败状态才允许提交审核
		if(!(WarehouseDictEnum.OUTBOUND_CREATED.getCode().equals(wmsOutOrdersEntity.getStatus())
				|| WarehouseDictEnum.OUTBOUND_REJECTED.getCode().equals(wmsOutOrdersEntity.getStatus()))){
			throw new JeecgBootException("非初始状态、审核失败状态出库单不允许审核");
		}
		//更新状态为提交审核
		wmsOutOrdersEntity.setStatus(WarehouseDictEnum.OUTBOUND_SUBMIT_AUDIT.getCode());
		updateById(wmsOutOrdersEntity);
	}

	@Override
	public void audit(WmsOutOrders wmsOutOrders) {
		//如果没有选择出库单则返回错误
		if(oConvertUtils.isEmpty(wmsOutOrders.getId())){
			//抛出异常
			throw new JeecgBootException("请选择要审核的出库单");
		}
		WmsOutOrders wmsOutOrdersEntity = getById(wmsOutOrders.getId());
		if(wmsOutOrdersEntity==null) {
			//异常
			throw new JeecgBootException("出库单不存在");
		}
		//当前状态只能是提交审核状态
		if(!WarehouseDictEnum.OUTBOUND_SUBMIT_AUDIT.getCode().equals(wmsOutOrdersEntity.getStatus())){
			//异常
			throw new JeecgBootException("当前状态是提交审核状态方可进行审核");
		}
		// todo 校验出库单的完整性

		//更新状态为审核通过或审核不通过
		wmsOutOrdersEntity.setStatus(wmsOutOrders.getStatus());
		updateById(wmsOutOrdersEntity);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public String allocateStockToItems(WmsOutOrdersItems item, List<WmsInventory> availableStocks) {

		//遍历可用库存
		for(WmsInventory inventory:availableStocks){
			//商品计划分配数量
			Integer expectedQuantity = item.getExpectedQuantity();
			//已分配数量
			Integer allocatedQuantity = item.getAllocatedQuantity();
			//剩余分配数量
			Integer remainingQuantity = expectedQuantity - allocatedQuantity;
			//如果分配完成，退出循环
			if(remainingQuantity<=0){
				break;
			}
			//可用库存数量
			Integer availableQuantity = inventory.getAvailableQuantity();
			if(availableQuantity<=0){
				continue;
			}
			//本次要分配数量
			Integer allocateQuantity = Math.min(availableQuantity, remainingQuantity);

			//向库存分配表插入记录
			WmsOutOrdersAllocation wmsOutOrdersAllocation = new WmsOutOrdersAllocation();
			wmsOutOrdersAllocation.setOrderId(item.getOrderId());
			wmsOutOrdersAllocation.setOrderItemId(item.getId());
			wmsOutOrdersAllocation.setSkuId(item.getSkuId());
			wmsOutOrdersAllocation.setLocationCode(inventory.getLocationCode());
			wmsOutOrdersAllocation.setBatchNumber(inventory.getBatchNumber());
			wmsOutOrdersAllocation.setContainerCode(inventory.getContainerCode());
			wmsOutOrdersAllocation.setAllocatedQuantity(allocateQuantity);
			wmsOutOrdersAllocation.setInventoryId(inventory.getId());
			outOrdersAllocationService.save(wmsOutOrdersAllocation);

			//锁定库存
			WmsInventoryTransParam wmsInventoryTransParam = new WmsInventoryTransParam();
			wmsInventoryTransParam.setProductId(item.getSkuId());
			wmsInventoryTransParam.setExecQuantity(allocateQuantity);
			wmsInventoryTransParam.setSourceLocationCode(inventory.getLocationCode());
			wmsInventoryTransParam.setWarehouseId(inventory.getWarehouseId());
			wmsInventoryTransParam.setBatchNumber(inventory.getBatchNumber());
			wmsInventoryTransParam.setTransactionType(WarehouseDictEnum.INVENTORY_ALLOCATION.getCode());
			wmsInventoryTransParam.setOperationTime(new Date());
			wmsInventoryTransByAllocation.transfer(wmsInventoryTransParam);

			//更新出库单明细中分配数量
			wmsOutOrdersItemsService.allocateStock(item.getId(), allocateQuantity,expectedQuantity);
			//查询最新的item
			item = wmsOutOrdersItemsService.getById(item.getId());


		}
		//更新出库单明细的状态(已分配或分配失败)
		String allocateStatus = wmsOutOrdersItemsService.updateAllocateStatus(item.getId());

		return allocateStatus;
	}


	@Override
	public List<WmsOutOrders> selectByMainId(String mainId) {
		return wmsOutOrdersMapper.selectByMainId(mainId);
	}

	@Override
	public List<WmsOutOrders> selectByWaveId(String waveId) {
		//根据波次id查询其下的出库单id
		List<WmsOutOrders> wmsOutOrders = wmsOutOrdersMapper.selectList(new LambdaQueryWrapper<WmsOutOrders>().eq(WmsOutOrders::getWaveId, waveId));
		return wmsOutOrders;
	}

	/**
	 * 获取未分配波次的出库单,状态为已分配 ALLOCATED
	 */
	public List<WmsOutOrders> selectUnassignedOrders(String warehouseId){
		return wmsOutOrdersMapper.selectUnassignedOrders(warehouseId);
	}
	/**
	 * 根据出库单id更新订单的波次ID
	 */
	public void batchUpdateWaveId( List<String> orderIds, String waveId,String shipmentStrategy){
		wmsOutOrdersMapper.batchUpdateWaveId(orderIds, waveId,shipmentStrategy);
	}

}
